package org.example.aienglishapp_login.config.login;

import org.example.aienglishapp_login.service.login.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

/**
 * JWT 令牌过滤器。
 * <p>
 * 该类继承自 {@link OncePerRequestFilter}，用于拦截 HTTP 请求并验证 JWT 令牌。
 * 如果验证通过，则设置 Spring Security 上下文中的认证信息。
 *
 * @author xlj
 * @version 1.0
 * @since 2024-10-1
 */
@Component
public class JwtTokenFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenFilter.class);

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtUtil jwtUtil;

    /**
     * 处理每次请求的核心方法。
     * <p>
     * 此方法会在每次 HTTP 请求时被调用，用于检查请求头中的 Authorization 字段，
     * 验证 JWT 令牌，并在验证成功后设置 Spring Security 的认证信息。
     *
     * @param request     客户端发送的 HTTP 请求
     * @param response    服务器返回给客户端的 HTTP 响应
     * @param filterChain 过滤器链，用于将请求传递给下一个过滤器或目标资源
     * @throws ServletException 如果处理过程中发生 Servlet 相关错误
     * @throws IOException      如果处理过程中发生 I/O 错误
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // 处理预检请求（CORS）
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        final String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String jwt = null;

        // 检查 Authorization 头部是否包含有效的 Bearer Token
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            try {
                username = jwtUtil.getUsernameFromToken(jwt);
                logger.info("令牌验证通过，从中提取的用户名: {}", username);
            } catch (Exception e) {
                logger.warn("令牌验证失败,未提取到用户名: {}", e.getMessage());
            }
        }

        // 如果从令牌中提取到了用户名，并且当前上下文中没有认证信息，则进行用户认证
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

            // 验证令牌是否有效
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }

        // 继续执行过滤器链中的下一个过滤器或目标资源
        filterChain.doFilter(request, response);
    }
}